package cn.mw.cmdb.virtualization.service.impl;

import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.mongoMapper.InstanceInfoMapper;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.template.utils.TemplateSortUtil;
import cn.mw.cmdb.virtualization.constant.MwVirtualizationConstant;
import cn.mw.cmdb.virtualization.dto.*;
import cn.mw.cmdb.virtualization.dto.unicloud.UniCloudVsWitchDto;
import cn.mw.cmdb.virtualization.param.VirtualizationParam;
import cn.mw.cmdb.virtualization.service.MwVirtualizationService;
import cn.mw.cmdb.virtualization.service.handler.UniCloudVsWitchHandler;
import cn.mw.cmdb.virtualization.service.handler.VirtualizationTreeHandler;
import cn.mw.cmdb.virtualization.strategy.SyncEngineQueryManager;
import cn.mw.cmdb.virtualization.strategy.VirtualizationTypeManager;
import cn.mw.cmdb.virtualization.utils.VirtualizationDataFilterUtil;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.main.api.common.ZabbixDubboService;
import cn.mw.microMonitorCommon.api.common.MwEngineManageService;
import cn.mw.microMonitorCommon.constants.ZabbixApiConstants;
import cn.mw.microMonitorCommon.entity.common.MwSyncEngineDto;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixAPIResult;
import cn.mw.microMonitorCommon.enums.SyncEngineTypeEnum;
import cn.mw.microMonitorCommon.enums.UnicloudTypeEnum;
import cn.mw.microMonitorCommon.enums.VcenterTypeEnum;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static cn.mw.cmdb.entity.InstanceInfo.SearchPrefix;
import static cn.mw.cmdb.processor.MonitorValue.MonitorTypeIdKey;

/**
 * @author gengjb
 * @description 虚拟化实现类
 */
@Service
@Slf4j
public class MwVirtualizationServiceImpl implements MwVirtualizationService {
    public static final String monitorTypeIdPath = SearchPrefix + "." + MonitorTypeIdKey;
    public static final String monitorSystemTypePath = SearchPrefix + "." + MwVirtualizationConstant.OPERATE_SYSTEM;


    @Autowired
    private CmdbServiceManage cmdbServiceManage;

    @DubboReference(check = false, timeout = 10000000)
    private ZabbixDubboService zabbixDubboService;

    @Autowired
    private InstanceInfoMapper instanceInfoMapper;

    @Autowired
    private VirtualizationTypeManager virtualizationTypeManager;

    @DubboReference(check = false, timeout = 10000000)
    private MwEngineManageService engineManageService;

    @Autowired
    private SyncEngineQueryManager syncEngineQueryManager;

    @Autowired
    private UniCloudVsWitchHandler uniCloudVsWitchHandler;

    @Override
    public void instanceRelationData(VirtualizationParam param) {
        try {
            param.setSyncFlag(false);
            List<InstanceInfo> instanceInfoList = getInstanceInfo(param);
            log.info("MwVirtualizationServiceImpl{} instanceRelationData() instanceInfoList>>>>>"+instanceInfoList);
            Map<String, VirtualizationDataConvertDto> dtoMap = getZabbixDataInfo(instanceInfoList, param.getServerId());
            log.info("MwVirtualizationServiceImpl{} instanceRelationData() dtoMap>>>>>"+dtoMap);
            List<Pair<Query, Update>> updateList = new ArrayList<>();
            //UNORDERED是异步执行，有错误跳过继续执行；ORDERED时有序执行，遇到错误终止
            BulkOperations operations = instanceInfoMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, InstanceInfo.class);
            for (InstanceInfo instanceInfo : instanceInfoList) {
                Map<String, Object> dataMap = instanceInfo.getData();
                //获取UUID
                if (!dataMap.containsKey(MwVirtualizationConstant.UUID)) {
                    continue;
                }
                String dataId = (String) dataMap.get(MwVirtualizationConstant.UUID);
                log.info("MwVirtualizationServiceImpl{} instanceRelationData() dataId>>>>>"+dataId);
                VirtualizationDataConvertDto dto = null;
                if(StringUtils.isNotEmpty(dataId) && dataId.contains(",")){
                    String[] uuids = dataId.split(",");
                    for (String uuid : uuids) {
                        if(dtoMap.get(uuid) != null){
                            dto = dtoMap.get(uuid);
                        }
                    }
                }else{
                    dto = dtoMap.get(dataId);
                }
                if(dto == null){
                    log.info("MwVirtualizationServiceImpl{} instanceRelationData() dto>>>>>"+dto);
                    continue;
                }
                Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).is(instanceInfo.getId()));
                log.info("convertUpdateByInstance::" + instanceInfo);
                //根据map字段产生更新信息
                Update update = new Update();
                log.info("MwVirtualizationServiceImpl{} instanceRelationData() hostid>>>>>"+dto.getHostid());
                update.set(monitorTypeIdPath, dto.getHostid());
                update.set(SearchPrefix + "." + MwVirtualizationConstant.SYNC_FLAG,true);
                try {
                    setOperateSystemName(dto.getName(),update);
                }catch (Throwable e){
                    log.info(new Date() + "::setOperateSystemName::",e);
                }
                Pair<Query, Update> updatePair = Pair.of(query, update);
                updateList.add(updatePair);
                log.info(new Date() + "::updatePair::" + updatePair);
            }
            operations.updateMulti(updateList);
            log.info(new Date() + "::updateList::" + updateList);
            if(CollectionUtils.isNotEmpty(updateList)){
                operations.execute();
            }
        } catch (Throwable e) {
            log.error("关联虚拟化资产失败:", e);
        }
    }

    private void setOperateSystemName(String name,Update update){
        if(StringUtils.isNotEmpty(name) && name.contains(">")){
            Pattern pattern = Pattern.compile("<(.*?)>");
            Matcher matcher = pattern.matcher(name);
            if (matcher.find()) {
                update.set(monitorSystemTypePath,matcher.group(1));
            }
        }
    }



    @Override
    public List<VirtualizationTreeDto> getVirtualizationTree(VirtualizationParam param) throws Exception {
        List<InstanceInfo> instanceInfoList = getInstanceInfo(param);
        List<VirtualizationTreeDataDto> nodes = new ArrayList<>();
        //数据转换
        for (InstanceInfo instanceInfo : instanceInfoList) {
            //排除存储数据
            Map<String, Object> infoData = instanceInfo.getData();
            if(infoData.containsKey(MwVirtualizationConstant.VM_TYPE)){
                String type = (String) infoData.get(MwVirtualizationConstant.VM_TYPE);
                if(type.equals(VcenterTypeEnum.DATASTORE.getType()) || type.equals(UnicloudTypeEnum.VS_WITCH.getType())){
                    continue;
                }
            }
            VirtualizationTreeDataDto treeDataDto = new VirtualizationTreeDataDto();
            treeDataDto.extractFrom(instanceInfo,param.getInstanceId());
            nodes.add(treeDataDto);
        }
        VirtualizationTreeDataDto dto = new VirtualizationTreeDataDto();
        dto.setName(param.getInstanceName());
        dto.setId(param.getInstanceId());
        dto.setEngineId(param.getEngineId());
        nodes.add(dto);
        Map<String, List<VirtualizationTreeDataDto>> childrenMap = new HashMap<>();
        List<VirtualizationTreeDto> roots = new ArrayList<>();
        // 创建一个孩子节点映射
        for (VirtualizationTreeDataDto node : nodes) {
            childrenMap.computeIfAbsent(node.getPid(), k -> new ArrayList<>()).add(node);
        }
        // 递归构建树
        for (VirtualizationTreeDataDto node : nodes) {
            if (StringUtils.isEmpty(node.getPid()) || node.getPid().equals(node.getId())) {
                roots.add(buildTreeNode(node, childrenMap));
            }
        }
        //设置基本信息
        VirtualizationTreeHandler treeHandler = new VirtualizationTreeHandler();
        treeHandler.handler(roots);
        return roots;
    }

    private static VirtualizationTreeDto buildTreeNode(VirtualizationTreeDataDto node, Map<String, List<VirtualizationTreeDataDto>> childrenMap) {
        VirtualizationTreeDto treeNode = new VirtualizationTreeDto(node);
        List<VirtualizationTreeDataDto> children = childrenMap.get(node.getId());
        if (children != null) {
            treeNode.getTreeDataDto().setCount(children.size());
            for (VirtualizationTreeDataDto child : children) {
                treeNode.addChild(buildTreeNode(child, childrenMap));
            }
            treeNode.extractFrom(node);
            treeNode.setTreeDataDto(null);
        }else{
            treeNode.getTreeDataDto().setCount(0);
            treeNode.extractFrom(node);
            treeNode.setTreeDataDto(null);
        }
        return treeNode;
    }

    private List<InstanceInfo> getInstanceInfo(VirtualizationParam param) throws Exception {
        //根据数据源ID查询当前虚拟化下的所有虚拟主机信息
        InstanceServiceImpl service = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
        Map data = new HashMap();
        if(StringUtils.isNotEmpty(param.getEngineId())){
            data.put(MwVirtualizationConstant.ENGINE_ID, param.getEngineId());
        }
        if(CollectionUtils.isNotEmpty(param.getInstanceIds())){
            instanceSearchParam.setInstanceIds(param.getInstanceIds());
        }
        if(StringUtils.isNotEmpty(param.getVmType())){
            data.put(MwVirtualizationConstant.VM_TYPE, param.getVmType());
        }
        if(param.getSyncFlag() != null){
            data.put(MwVirtualizationConstant.SYNC_FLAG, param.getSyncFlag());
        }
        if(!data.isEmpty()){
            instanceSearchParam.setData(data);
        }
        instanceSearchParam.convert();
        List<InstanceInfo> instanceInfoList = service.doSelectList(instanceSearchParam);
        return instanceInfoList;
    }

    private Map<String, VirtualizationDataConvertDto> getZabbixDataInfo( List<InstanceInfo> instanceInfoList,Integer serverId){
        ArrayList<String> ids = new ArrayList<>();
        for (InstanceInfo instanceInfo : instanceInfoList) {
            Map<String, Object> dataMap = instanceInfo.getData();
            //获取UUID
            if (!dataMap.containsKey(MwVirtualizationConstant.UUID)) {
                continue;
            }
            String dataId = (String) dataMap.get(MwVirtualizationConstant.UUID);
            if(StringUtils.isNotEmpty(dataId) && dataId.contains(",")){
                ids.addAll(Arrays.asList(dataId.split(",")));
                continue;
            }
            if (StringUtils.isNotEmpty(dataId)) {
                ids.add(dataId);
            }
        }
        log.info("MwVirtualizationServiceImpl{} getZabbixDataInfo() ids>>>>>"+ids);
        //根据服务ID与uuid查询zabbix上的虚拟化资产主机ID并同步
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.HOST_LIST_GET_BY_HOST_NAME, serverId, ids);
        log.info("MwVirtualizationServiceImpl{} getZabbixDataInfo() mwZabbixAPIResult>>>>>"+mwZabbixAPIResult);
        if (mwZabbixAPIResult == null || mwZabbixAPIResult.isFail()) {
            return null;
        }
        List<VirtualizationDataConvertDto> virtualizationDataConvertDtos = JSONArray.parseArray(String.valueOf(mwZabbixAPIResult.getData()), VirtualizationDataConvertDto.class);
        Map<String, VirtualizationDataConvertDto> convertDtoMap = virtualizationDataConvertDtos.stream().collect(Collectors.toMap(s -> s.getHost(), s -> s));
        return convertDtoMap;
    }

    @Override
    public Page getVirtualizationStorageInfo(VirtualizationParam param) throws Exception {
        //获取引擎信息
        String engineId = param.getEngineId();
        //查询引擎信息
        MwSyncEngineDto engineDto = engineManageService.getSyncEngineByEngineId(Integer.parseInt(engineId));
        //调用不同的存储数据查询
        SyncEngineTypeEnum engineTypeEnum = engineDto.getEngineType();
        List<VirtualizationStorageDto> storageDtos = syncEngineQueryManager.handlerSyncEngineData(engineTypeEnum, param, engineDto);
        //排序处理
        if(StringUtils.isNotEmpty(param.getSortName()) && StringUtils.isNotEmpty(param.getSortOrder())){
            SearchParam searchParam = new SearchParam();
            searchParam.setSortName(param.getSortName());
            searchParam.setSortOrder(param.getSortOrder());
            List list = TemplateSortUtil.templateSortList(storageDtos, searchParam, null);
            list = VirtualizationDataFilterUtil.dataFilter(list, param.getQueryKey(), param.getQueryValue());
            //分页
            Page page = pageHandler(list, param.getPageNum(), param.getPageSize());
            return page;
        }
        List dataInfo = VirtualizationDataFilterUtil.dataFilter(storageDtos, param.getQueryKey(), param.getQueryValue());
        //分页
        Page page = pageHandler(dataInfo, param.getPageNum(), param.getPageSize());
        return page;
    }

    @Override
    public Object getVirtualizationBasicInfo(VirtualizationParam param) throws Exception {
        //获取实例
        List<InstanceInfo> instanceInfo = getInstanceInfo(param);
        List<VirtualizationBaseDto> baseDtos = new ArrayList<>();
        //获取所有的hostId
        for (InstanceInfo info : instanceInfo) {
            VirtualizationBaseDto baseDto = new VirtualizationBaseDto();
            baseDto.extractFrom(info);
            baseDtos.add(baseDto);
        }
        Object data = virtualizationTypeManager.getTypeData(param.getQueryType(), baseDtos, param, param.getServerId());
        return data;
    }


    @Override
    public void syncVirtualizationData(VirtualizationParam param) {
        log.info("MwVirtualizationServiceImpl{} syncVirtualizationData() engineId()>>>"+param.getEngineId());
        //获取引擎信息
        MwSyncEngineDto engineDto = engineManageService.getSyncEngineByEngineId(Integer.parseInt(param.getEngineId()));
        log.info("MwVirtualizationServiceImpl{} syncVirtualizationData() engineDto()>>>"+engineDto);
        syncEngineQueryManager.syncData(engineDto.getEngineType(),param,engineDto);
        log.info("MwVirtualizationServiceImpl{} syncVirtualizationData() RelationData>>>"+param);
        //同步后进行数据zabbix同步
        instanceRelationData(param);
    }

    @Override
    public Page getUniCloudVsWitchInfo(VirtualizationParam param) throws Exception {
        List<UniCloudVsWitchDto> uniCloudVsWitchInfo = uniCloudVsWitchHandler.getUniCloudVsWitchInfo(param, cmdbServiceManage);
        List dataInfo = VirtualizationDataFilterUtil.dataFilter(uniCloudVsWitchInfo, param.getQueryKey(), param.getQueryValue());
        //分页
        Page page = pageHandler(dataInfo, param.getPageNum(), param.getPageSize());
        return page;
    }


    private Page pageHandler(List realDatas, Integer pageNum,Integer pageSize){
        if(CollectionUtils.isNotEmpty(realDatas)){
            //根据分页信息分割数据
            int fromIndex = pageSize * (pageNum -1);
            int toIndex = pageSize * pageNum;
            if(toIndex > realDatas.size()){
                toIndex = realDatas.size();
            }
            List<Map<String,Object>> pageList = realDatas.subList(fromIndex, toIndex);
            Page page = new Page();
            page.setRecords(pageList);
            page.setTotal(realDatas.size());
            return page;
        }
        return new Page();
    }
}
